import pyglet
from pyglet.gl import *


class GameState:
    """Abstract game state class

    Game states are event handlers that encapsulate
    a particular mode of the game window
    """

    def enter(self, window):
        """Called when state is entered"""
    
    def exit(self, window):
        """Called when state is exited"""
    
    def update(self, dt):
        """Called periodically to update the state when active"""
        pass


class GameWindow(pyglet.window.Window):
    
    def __init__(self, fps=60, **kw):
        super(GameWindow, self).__init__(**kw)
        self.states = []
        self.queued_states = []
        self.fps = fps
        self.max_dt = (1.0/fps) * 10.0
        pyglet.clock.schedule_interval(self.update, 1.0/fps)
    
    def push_state(self, state):
        self.queued_states.append(state)
    
    def pop_state(self):
        if self.queued_states:
            self.queued_states.pop()
        else:
            old_state = self.states.pop()
            self.pop_handlers()
            old_state.exit(self)
            if self.states:
                new_state = self.states[-1]
                self.push_handlers(new_state)
                new_state.enter(self)
            else:
                # No more states, we're done
                self.close()
    
    def update(self, dt):
        if self.queued_states:
            if self.states:
                self.pop_handlers()
                self.states[-1].exit(self)
            self.states.extend(self.queued_states)
            self.queued_states = []
            self.push_handlers(self.states[-1])
            self.states[-1].enter(self)
        if dt > self.max_dt:
            dt = self.max_dt # smooth out dt spikes
        if self.states:
            self.states[-1].update(dt)

    def on_resize(self, width, height):
        glViewport(0, 0, width, height)
        self.clear()


_window = None

def create_window(**kw):
    """Create the game window singleton"""
    global _window
    _window = GameWindow(**kw)
    return _window

def get_window():
    """Return the current game window"""
    global _window
    return _window

def clear_window():
    """Clear the current game window"""
    global _window
    _window.clear()
